package com.base.util;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.net.Uri;
import android.provider.MediaStore;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.loyal.core.helper.TimeHelper;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class ImageUtil {
    /**
     * 竖屏照片尺寸(width < height)
     */
    private static final int WIDTH_P = 720;
    private static final int HEIGHT_P = 1280;
    /**
     * 横屏照片尺寸(width > height)
     */
    private static final int WIDTH_L = 1280;
    private static final int HEIGHT_L = 720;
    /**
     * 手机拍照图片压缩后最大不超过100K
     */
    public static final int COMPRESS_SIZE_CAMERA = 100;
    /**
     * 远程抓拍图片大小限制在800K
     */
    public static final int COMPRESS_SIZE_CAPTURE = 800;

    /**
     * 添加水印
     */
    public static boolean saveCropImage(byte[] data, String imgPath, String text, boolean needCrop) {
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeByteArray(data, 0, data.length, options);
            int outWidth = options.outWidth;
            int outHeight = options.outHeight;

            int rate = 1;
            if (outWidth > outHeight && outWidth > WIDTH_L) {// 如果宽度大的话根据宽度固定大小缩放
                rate = outWidth / WIDTH_L;
            } else if (outWidth < outHeight && outHeight > HEIGHT_L) {// 如果高度高的话根据宽度固定大小缩放
                rate = outHeight / HEIGHT_L;
            }
            if (rate <= 0) {
                rate = 1;
            }
            options.inSampleSize = rate;
            options.inJustDecodeBounds = false;
            Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
            if (needCrop) {
                Matrix m = new Matrix();
                int bmpWidth = bitmap.getWidth();
                int bmpHeight = bitmap.getHeight();
                int height = Math.min(bmpHeight, 200);
                int retY = ((Math.max(bmpHeight, 200)) - 200) / 2;
                // 以当前自己的原点旋转多少度
                m.setRotate(0, bmpWidth / 2f, bmpHeight / 2f);
                Bitmap rotatedImage = Bitmap.createBitmap(bitmap, 0, retY, bmpWidth, height, m, true);
                if (rotatedImage != bitmap) {
                    bitmap.recycle();
                }
                bitmap = rotatedImage;
            }
            String dateTime = TimeHelper.getDateTime();
            String mark = String.format("%s\n%s", dateTime, text);
            Log.e("saveCropImage", ": mark=" + mark);
            Bitmap textBmp = createPhotoWithText(bitmap, mark);
            boolean success = saveBitmap(imgPath, textBmp, true);
            if (bitmap != null && !bitmap.isRecycled()) {
                bitmap.recycle();
            }
            if (textBmp != null && !textBmp.isRecycled()) {
                textBmp.recycle();
            }
            return success;
        } catch (Exception e) {
            return false;
        }
    }

    public static boolean saveByteArray(byte[] data, String imgPath) {
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeByteArray(data, 0, data.length, options);
            int outWidth = options.outWidth;
            int outHeight = options.outHeight;

            int rate = 1;
            if (outWidth > outHeight && outWidth > WIDTH_L) {// 如果宽度大的话根据宽度固定大小缩放
                rate = outWidth / WIDTH_L;
            } else if (outWidth < outHeight && outHeight > HEIGHT_L) {// 如果高度高的话根据宽度固定大小缩放
                rate = outHeight / HEIGHT_L;
            }
            if (rate <= 0) {
                rate = 1;
            }
            options.inSampleSize = rate;
            options.inJustDecodeBounds = false;

            Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
            boolean success = saveBitmap(imgPath, bitmap, true);
            if (bitmap != null) {
                bitmap.recycle();
            }
            return success;
        } catch (Exception e) {
            return false;
        }
    }

    public static boolean saveImageByteArray(byte[] data, String imgPath, float degree) {
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeByteArray(data, 0, data.length, options);
            int outWidth = options.outWidth;
            int outHeight = options.outHeight;

            int rate = 1;
            if (outWidth > outHeight && outWidth > WIDTH_L) {// 如果宽度大的话根据宽度固定大小缩放
                rate = outWidth / WIDTH_L;
            } else if (outWidth < outHeight && outHeight > HEIGHT_L) {// 如果高度高的话根据宽度固定大小缩放
                rate = outHeight / HEIGHT_L;
            }
            if (rate <= 0) {
                rate = 1;
            }
            options.inSampleSize = rate;
            options.inJustDecodeBounds = false;

            Bitmap sourceBmp = BitmapFactory.decodeByteArray(data, 0, data.length, options);
            Bitmap rotateBmp = rotateBitmap(sourceBmp, degree);
            boolean result = saveBitmap(imgPath, rotateBmp, true);
            if (null != rotateBmp && !rotateBmp.isRecycled()) {
                rotateBmp.recycle();
            }
            return result;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * Bitmap旋转
     *
     * @param degrees 旋转角度
     */
    public static @Nullable
    Bitmap rotateBitmap(@Nullable Bitmap bitmap, float degrees) {
        if (null == bitmap) {
            return null;
        }
        try {
            int width = bitmap.getWidth();
            int height = bitmap.getHeight();
            Matrix matrix = new Matrix();
            // 以当前自己的原点旋转多少度
            matrix.setRotate(degrees, width / 2f, height / 2f);
            Bitmap rotateBmp = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
            if (rotateBmp != bitmap) {
                bitmap.recycle();
            }
            return rotateBmp;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 文件转Base64
     *
     * @param imgPath 文件地址
     */
    public static String image2Base64(String imgPath) {
        return image2Base64(new File(imgPath));
    }

    /***/
    public static String image2Base64(File imgFile) {
        try {
            byte[] bytes = MemoryUtil.readByteArray(imgFile);
            // 对字节数组Base64编码
            return Base64.encodeToString(bytes, Base64.DEFAULT);
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * base64转bitmap
     */
    public static @Nullable
    Bitmap base64ToBmp(String base64) {
        return base64ToBmp(base64, Base64.DEFAULT);
    }

    public static @Nullable
    Bitmap base64ToBmp(String base64, int flag) {
        try {
            if (TextUtils.isEmpty(base64))
                return null;
            final String base64Prefix = "data:image/";
            if (base64.startsWith(base64Prefix)) {//截取开头类似 data:image/jpeg;base64,
                base64 = base64.split(",")[1];
            }
            byte[] decode = Base64.decode(base64, flag);
            return BitmapFactory.decodeByteArray(decode, 0, decode.length);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 质量压缩保存图片文件
     */
    public static boolean saveBitmap(String imgPath, Bitmap bitmap, boolean compress) {
        if (null == bitmap || TextUtils.isEmpty(imgPath)) {
            return false;
        }
        File jpgFile = new File(imgPath);

        try (FileOutputStream outputStream = new FileOutputStream(jpgFile)) {
            outputStream.write(compress(bitmap, compress));
            outputStream.flush();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public static @Nullable byte[] compress(@NonNull Bitmap bitmap, boolean compress) {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            // 质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
            int quality = 70;

            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
            if (compress) {
                // 循环判断如果压缩后图片是否大于100kb,大于继续压缩
                while (baos.toByteArray().length / 1024 > COMPRESS_SIZE_CAMERA) {
                    // 重置baos即清空baos
                    baos.reset();
                    // 每次都减少10
                    quality -= 5;
                    // 这里压缩options%，把压缩后的数据存放到baos中
                    bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
                }
            }
            return baos.toByteArray();
        } catch (Exception e) {
            return null;
        }
    }

    public static String uriToPath(Context context, Uri imgUri) {
        if (null == context || null == imgUri) {
            return "";
        }
        String[] filePathColumn = {MediaStore.MediaColumns.DATA};
        //查询我们需要的数据
        ContentResolver contentProvider = context.getContentResolver();
        try (Cursor cursor = contentProvider.query(imgUri, filePathColumn, null, null, null)) {
            cursor.moveToFirst();
            int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
            String imgPath = cursor.getString(columnIndex);
            Log.e("选择图片地址", imgPath);
            return imgPath;
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * uri转bitmap
     */
    public static @Nullable Bitmap uriToBmp(Context context, Uri uri) {
        if (null == context || null == uri) {
            return null;
        }
        try {
            ContentResolver resolver = context.getContentResolver();
            BitmapFactory.Options newOpts = new BitmapFactory.Options();
            newOpts.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(resolver.openInputStream(uri), null, newOpts);
            int w = newOpts.outWidth;
            int h = newOpts.outHeight;
            float hh = 800f;
            float ww = 480f;
            int be = 1;
            if (w > h && w > ww) {
                be = (int) (newOpts.outWidth / ww);
            } else if (w < h && h > hh) {
                be = (int) (newOpts.outHeight / hh);
            }
            if (be <= 0) {
                be = 1;
            }
            newOpts.inSampleSize = be;
            newOpts.inJustDecodeBounds = false;

            Bitmap bitmap = BitmapFactory.decodeStream(resolver.openInputStream(uri), null, newOpts);
            ByteArrayInputStream isBm = new ByteArrayInputStream(compress(bitmap, true));
            return BitmapFactory.decodeStream(isBm, null, null);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * uri转bitmap
     */
    public static @Nullable Bitmap pathToBmp(String imgPath) {
        if (TextUtils.isEmpty(imgPath)) {
            return null;
        }
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        newOpts.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(imgPath, newOpts);
        int w = newOpts.outWidth;
        int h = newOpts.outHeight;
        float hh = 800f;
        float ww = 480f;
        int be = 1;
        if (w >= h && w >= ww) {
            be = (int) (newOpts.outWidth / ww);
        } else if (w < h && h > hh) {
            be = (int) (newOpts.outHeight / hh);
        }
        if (be <= 0) {
            be = 1;
        }
        newOpts.inSampleSize = be;
        newOpts.inJustDecodeBounds = false;
        Bitmap bitmap = BitmapFactory.decodeFile(imgPath, newOpts);
        try (ByteArrayInputStream isBm = new ByteArrayInputStream(compress(bitmap, true))) {
            return BitmapFactory.decodeStream(isBm, null, null);
        } catch (Exception e) {
            return null;
        }
    }

    public static @Nullable Bitmap createPhotoWithText(Bitmap bitmap, String text) {
        try {
            if (null == bitmap) {
                return null;
            }
            int width = bitmap.getWidth();
            int height = bitmap.getHeight();
            Bitmap newBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(newBitmap);
            canvas.drawBitmap(bitmap, 0, 0, null);
            bitmap.recycle();
            TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
            textPaint.setColor(Color.RED);
            int textSize = 45;
            textPaint.setTextSize(textSize);
            textPaint.setTypeface(Typeface.DEFAULT_BOLD);
            //根据图片宽度设置文字文字，使文字居右底端显示
            int newStringWidth = (int) (width * 0.8f);
            // 文字矩阵区域
            Rect textBounds = new Rect();
            textPaint.getTextBounds(text, 0, text.length(), textBounds);

            //计算文字坐标 预留20个像素
            int stringX = 15;
            int stringY = 15;
            //canvas.drawText(text, stringX, stringY, paint);

            StaticLayout layout = new StaticLayout(text, textPaint, width / 2,
                    Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true);
            // 画文字
            canvas.translate(stringX, stringY);
            layout.draw(canvas);
            //保存所有元素
            canvas.save();
            canvas.restore();
            return newBitmap;
        } catch (Exception e) {
            return null;
        }
    }

    public static String buildImgName(String zpDm) {
        return String.format("%s.jpg", zpDm);
    }

    /**
     * bitmap转base64
     */
    public static @Nullable String signToBase64(Bitmap bitmap) {
        return bmpToBase64(bitmap, Bitmap.CompressFormat.PNG, Base64.NO_WRAP);
    }

    public static @Nullable String jpgBmpToBase64(Bitmap bitmap) {
        return bmpToBase64(bitmap, Bitmap.CompressFormat.JPEG, Base64.DEFAULT);
    }

    public static @Nullable String pngBmpToBase64(Bitmap bitmap) {
        return bmpToBase64(bitmap, Bitmap.CompressFormat.PNG, Base64.DEFAULT);
    }

    public static @Nullable String bmpToBase64(Bitmap bitmap, Bitmap.CompressFormat format, int flag) {
        if (null == bitmap || bitmap.isRecycled())
            return null;
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            bitmap.compress(format, 100, baos);
            baos.flush();
            byte[] bitmapBytes = baos.toByteArray();
            return Base64.encodeToString(bitmapBytes, flag);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 质量压缩保存图片文件
     */
    public static boolean savePngBitmap(String imgPath, Bitmap bitmap, boolean compress) {
        if (null == bitmap || TextUtils.isEmpty(imgPath))
            return false;
        File pngFile = new File(imgPath);
        try (FileOutputStream outputStream = new FileOutputStream(pngFile);
             ByteArrayOutputStream baos = new ByteArrayOutputStream()) {

            // 质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
            int quality = 100;

            bitmap.compress(Bitmap.CompressFormat.PNG, quality, baos);
            if (compress) {
                // 循环判断如果压缩后图片是否大于100kb,大于继续压缩
                while (baos.toByteArray().length / 1024 > COMPRESS_SIZE_CAMERA) {
                    // 重置baos即清空baos
                    baos.reset();
                    // 每次都减少10
                    quality -= 5;
                    // 这里压缩options%，把压缩后的数据存放到baos中
                    bitmap.compress(Bitmap.CompressFormat.PNG, quality, baos);
                }
            }

            outputStream.write(baos.toByteArray());
            outputStream.flush();
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public static boolean saveWebpBitmap(String imgPath, Bitmap bitmap, boolean compress) {
        if (null == bitmap || TextUtils.isEmpty(imgPath))
            return false;
        File pngFile = new File(imgPath);
        try (FileOutputStream outputStream = new FileOutputStream(pngFile);
             ByteArrayOutputStream baos = new ByteArrayOutputStream()) {

            // 质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
            int quality = 100;

            bitmap.compress(Bitmap.CompressFormat.WEBP, quality, baos);
            if (compress) {
                // 循环判断如果压缩后图片是否大于100kb,大于继续压缩
                while (baos.toByteArray().length / 1024 > COMPRESS_SIZE_CAMERA && quality > 10) {
                    // 重置baos即清空baos
                    baos.reset();
                    // 每次都减少10
                    quality -= 5;
                    // 这里压缩options%，把压缩后的数据存放到baos中
                    bitmap.compress(Bitmap.CompressFormat.WEBP, quality, baos);
                }
            }

            outputStream.write(baos.toByteArray());
            outputStream.flush();
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public static String uri2Path(Context context, Uri imgUri) {
        if (null == context || null == imgUri) return "";
        String[] filePathColumn = {MediaStore.Images.Media.DATA};
        //查询我们需要的数据
        ContentResolver contentProvider = context.getContentResolver();
        try (Cursor cursor = contentProvider.query(imgUri, filePathColumn, null, null, null)) {
            cursor.moveToFirst();
            int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
            String imgPath = cursor.getString(columnIndex);
            Log.e("选择图片地址", imgPath);
            return imgPath;
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * uri转bitmap
     */
    public static @Nullable
    Bitmap uri2Bmp(Context context, Uri uri) throws Exception {
        if (null == context || null == uri)
            return null;
        ContentResolver resolver = context.getContentResolver();
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        newOpts.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(resolver.openInputStream(uri), null, newOpts);
        int w = newOpts.outWidth;
        int h = newOpts.outHeight;
        float hh = 800f;
        float ww = 480f;
        int be = 1;
        if (w > h && w > ww) {
            be = (int) (newOpts.outWidth / ww);
        } else if (w < h && h > hh) {
            be = (int) (newOpts.outHeight / hh);
        }
        if (be <= 0)
            be = 1;
        newOpts.inSampleSize = be;
        newOpts.inJustDecodeBounds = false;
        try {
            Bitmap bitmap = BitmapFactory.decodeStream(resolver.openInputStream(uri), null, newOpts);
            ByteArrayInputStream isBm = new ByteArrayInputStream(compress(bitmap, true));
            return BitmapFactory.decodeStream(isBm, null, null);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * uri转bitmap
     */
    public static @Nullable
    Bitmap path2Bmp(String imgPath) {
        if (TextUtils.isEmpty(imgPath))
            return null;
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        newOpts.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(imgPath, newOpts);
        int w = newOpts.outWidth;
        int h = newOpts.outHeight;
        float hh = 800f;
        float ww = 480f;
        int be = 1;
        if (w >= h && w >= ww) {
            be = (int) (newOpts.outWidth / ww);
        } else if (w < h && h > hh) {
            be = (int) (newOpts.outHeight / hh);
        }
        if (be <= 0)
            be = 1;
        newOpts.inSampleSize = be;
        newOpts.inJustDecodeBounds = false;
        Bitmap bitmap = BitmapFactory.decodeFile(imgPath, newOpts);
        try (ByteArrayInputStream isBm = new ByteArrayInputStream(compress(bitmap, true))) {
            return BitmapFactory.decodeStream(isBm, null, null);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 加密，把一个字符串在原有的基础上+1
     *
     * @param data 需要解密的原字符串
     * @return 返回解密后的新字符串
     */
    public static String encode(String data) {
        if (TextUtils.isEmpty(data))
            return "";
        try {
            byte[] b = data.getBytes();
            for (int i = 0; i < b.length; i++) {
                b[i] += 1;//在原有的基础上+1
            }
            return new String(b);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 解密：把一个加密后的字符串在原有基础上-1
     *
     * @param data 加密后的字符串
     * @return 返回解密后的新字符串
     */
    public static String decode(String data) {
        if (TextUtils.isEmpty(data))
            return "";
        try {
            byte[] b = data.getBytes();
            //遍历
            for (int i = 0; i < b.length; i++) {
                b[i] -= 1;//在原有的基础上-1
            }
            return new String(b);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    public static boolean saveBase64(String base64, String savePath) {
        if (TextUtils.isEmpty(base64) || TextUtils.isEmpty(savePath))
            return false;
        Bitmap bitmap = base64ToBmp(base64);
        return saveBitmap(savePath, bitmap, true);
    }

    /**
     * 保存抓拍图
     */
    public static boolean saveCapture(String base64, String savePath) {
        if (TextUtils.isEmpty(base64) || TextUtils.isEmpty(savePath))
            return false;
        Bitmap bitmap = base64ToBmp(base64);
        return saveCaptureBitmap(savePath, bitmap);
    }

    /**
     * 质量压缩保存图片文件
     */
    public static boolean saveCaptureBitmap(String imgPath, Bitmap bitmap) {
        if (null == bitmap || TextUtils.isEmpty(imgPath)) {
            return false;
        }
        File jpgFile = new File(imgPath);

        try (FileOutputStream outputStream = new FileOutputStream(jpgFile)) {
            outputStream.write(compressBySize(bitmap, Bitmap.CompressFormat.JPEG, COMPRESS_SIZE_CAPTURE));
            outputStream.flush();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据size压缩
     */
    public static @Nullable
    byte[] compressBySize(@NonNull Bitmap bitmap, @NonNull Bitmap.CompressFormat format, int compressSize) {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            // 质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
            int quality = 100;
            bitmap.compress(format, quality, baos);

            // 循环判断如果压缩后图片是否大于xKB,大于继续压缩
            while (baos.toByteArray().length / 1024 > compressSize) {
                // 重置baos即清空baos
                baos.reset();
                // 每次都减少5
                quality -= 5;
                // 这里压缩options%，把压缩后的数据存放到baos中
                bitmap.compress(format, quality, baos);
            }
            return baos.toByteArray();
        } catch (Exception e) {
            return null;
        }
    }
}
